iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Modern Web

剛入行就一人重新打造公司前端系統?系列 第 29

Day 29 - 使用 useMemo 來做效能優化

  • 分享至 

  • xImage
  •  

useCallback 與 useMemo 都可以在 React 中來做效能優化,差別在於 useCallback 是拿來快取函式,而 useMemo 是拿來快取陣列或物件類型的資料。那今天就來介紹 useMemo~

useMemo

為什麼要叫 useMemo 呢?因為返回快取的值這技術稱為記憶化(Memoization),這就是這 React hook 的命名原因。那 useMemo 是用來記住運算結果,只有當依賴變化時,才會重新計算結果。

語法:

const cachedValue = useMemo(calculateValue, dependencies)
  • calculateValue:是一個函式,會計算要快取的值。要是純函式(pure function)。
  • dependencies :是一個陣列。
  • 運作流程:
    1. React 會在初次渲染時呼叫 calculateValue 這個函式,然後計算要快取的值並且回傳。
    2. 後續重新渲染時,React 會比較 dependencies :
      • 如果相同的話:會回傳前一次渲染所快取起來的值。
      • 如果不同的話:會呼叫 calculateValue 這個函式來重新計算,並且把計算後的值快取並且回傳。
      • 注意:useMemo 本身就可以用於節省計算而達到效能優化,這與昨天介紹的 useCallback 不太一樣(useCallback 無法避免每次渲染時重新產生函式)。

範例一、節省計算來達到效能優化

以下例子中,只有當 numbers 發生變化時,useMemo 才會重新計算總和。如果 numbers 沒有變化,那它會直接使用之前計算的結果。

import { useMemo } from 'react';

function SumArray({ numbers }) {

  const total = useMemo(() => {
    return numbers.reduce((acc, num) => acc + num, 0);
  }, [numbers]); // 只有當 numbers 改變時才重新計算

  return <div>總和:{total}</div>;
}
  • calculateValue 這個函式不會有引數 (Argument),像是 () ⇒ ,然後會回傳計算結果。

範例二、避免不必要的重新渲染

假設有一個顯示項目列表 會根據某些條件進行排序。

優化前

如果每次重新渲染都對列表進行排序,那可能會造成效能問題,特別是當列表項目數量較大時。

function ItemList({ items, sortBy }) {
  const sortedItems = items.sort((a, b) => {
    if (sortBy === 'asc') return a - b;
    if (sortBy === 'desc') return b - a;
  });

  return (
    <ul>
      {sortedItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

function Parent() {
  const items = [5, 3, 8, 1, 2];
  const sortBy = 'asc'; // 升序排列

  return <ItemList items={items} sortBy={sortBy} />;
}
  • 在這個例子中,每次重新渲染 ,都會重新對 items 進行排序,無論 items 是否發生變化。

優化後

import { useMemo } from 'react';

function ItemList({ items, sortBy }) {

  const sortedItems = useMemo(() => {
    return items.slice().sort((a, b) => {
      if (sortBy === 'asc') return a - b;
      if (sortBy === 'desc') return b - a;
    });
  }, [items, sortBy]); // 只有 items 或 sortBy 改變時才會重新排序

  return (
    <ul>
      {sortedItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

function Parent() {
  const items = [5, 3, 8, 1, 2];
  const sortBy = 'asc';

  return <ItemList items={items} sortBy={sortBy} />;
}
  • 使用 useMemo 可以避免在 itemssortBy 沒有改變時,重複執行排序操作。

所以是如何達到效能優化?

  • 只有當 itemssortBy 發生變化時,才會重新計算 sortedItems。這樣可以避免每次重新渲染都進行排序,從而提升效能,特別是在列表項目較多或計算成本較高的情況下。

參考資料


上一篇
Day 28 - useCallback 到底是如何達到效能優化的目的?
下一篇
Day 30 - 完賽心得
系列文
剛入行就一人重新打造公司前端系統?31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言